
# 封装
# 面相对象的三项对象：封装、继承、多态

# 封装：隐藏对象中一些不希望被外部所访问到的属性或者方法
class Person:
    name = "bingbing"
pe = Person()
print(pe.name)
Person.name = 'ziyi'
print(Person.name)

# 隐藏属性（私有权限）：只允许在类的内部使用，无法通过对象访问
# 在属性名或者方法名前面加上两个下划线
class Person1:
    name = "bingbing"
    __age = 28 #隐藏属性

    def introduce(self): #实例方法
        print(f"{Person1.name}的年龄{Person1.__age}")


p = Person1()
print(p.name)
# print(p.age)
# 如何访问隐藏属性
# 第一种：了解
# 隐藏属性实际上是将名字修改为：_类名__属性名(__Person__age)
print(p._Person1__age)
p._Person1__age = 18
print(p._Person1__age)
# 第二种 在类的内部访问
p.introduce()

# 私有属性/方法
# xxx:普通变量/方法
# _xxx:单下划线声明私有属性/方法，如果定义在类中，外部可以使用，子类可以继承，但在另一个py文件使用from xxxx impot * 时，无法导入
# 一般是为了避免与python关键字冲突而采用的命名方法
# __xxx:双下划线开头，隐藏属性，如果定义在类中，无法在外部直接访问，子类不会继承，访问只能通过间接的方式，另一个py文件通过from xxx import * 也无法导入
# 一般是python中的魔法属性/方法，都是有特殊含义或者功能的，自己不要轻易定义。

class Person3:
    name = "zhangsan"
    _age = 18 # 私有属性（单下划线）
    __sex = "男" # 隐藏属性（双下划线）
    def __play(self): #隐藏方法
        print("玩手机")
    def funa(self): #普通方法
        print("一个普通方法")
        # Person3.__play(self)  # 不推荐
        self.__play()  #推荐
    def _go(self):
        print("buy buy buy!")
pe = Person3()
print(pe._age) #使用对象名._属性名访问私有属性
print(pe._Person3__sex) #隐藏属性，一般通过内部访问，这里通过不正当手段访问
pe.funa()
# 访问隐藏方法
# pe._Person3__play()
# 访问私有方法
pe._go()


# 继承
# 就是让类和类之间转变为父子关系，子类默认继承父类的属性和方法
# 语法：
# class类名（父类名）
#     代码块.…
# 注意：继承分为单继承和多继承

# 单继承
class Person: #父类
    def eat(self):
        print("我会吃饭")
    def sing(self):
        print("我是唱歌小能手")

class Girl(Person):
    pass #占位符，代码里边类下边不写任何东西，会自动跳过，不会报错

# 1. pass 的作用
# 语法占位符：pass 是一个空语句，用于在代码结构中占位，保证语法完整性。它表示“此处无逻辑，但语法需要”
# 必要性：Python 要求类或函数的定义体不能为空。若省略 pass，会触发 IndentationError（缩进错误）或 SyntaxError（语法错误）
# class Girl(Person):
#     pass  # 空类体，但语法合法
# 2. None 的作用
# 空值对象：None 是 Python 中表示“空”或“无”的特殊值，属于 NoneType 类型，用于变量赋值或返回值，不能作为语句单独使用
# class Girl(Person):
#     None  # 语法错误！None 不能作为类体内容
# 3. 替代方案
# 使用 ...（Ellipsis）：在 Python 3+ 中，可以用 ... 替代 pass 作为占位符，但更推荐 pass 以提高可读性
# class Girl(Person):
#     ...  # 合法，但不如 pass 明确

girl = Girl()
girl.eat()
girl.sing()

# 总结：子类可以继承父类的属姓和方法就算子类自己没有也可以使用父类的

# 继承的传递（多重继承）
# A继承B，B继承C
class Father: # 父类
    def eat(self):
        print("吃饭")
    def sleep(self):
        print("睡觉")

class Son(Father): # Father类的子类
    pass

class GrandSon(Son): # Son的子类
    pass

son = Son()
son.eat()
son.sleep()

grandSon = GrandSon()
grandSon.eat()
grandSon.sleep()

# 继承的传递性就是子类拥有父类以及父类的父类中的属性和方法

# 方法的重写
# 含义：如果从父类继承的方法不能满足子类的需求，可以在子类中重写父类的方法，这个过程称为方法的覆盖，也称为方法的重写。
# 实现对父类方法进行扩展的三种方式：
# 1.父类名.方法名(self)
# 2.super().方法名()      --推荐使用 懒人写法
# super在python中是一个特殊的类，super()是使用super类创建出来的对象，可以调用父类中的方法
# 3.super(子类名，self).方法名

class Country:
    def city(self):
        print("shanxi xian")
class China(Country):
    def city(self):
        print("sichuan chengdu")

ch = China()
ch.city()

# 对父类方法扩展，继承父类方法，子类也可以增加自己的功能

class Person:
    def money(self):
        print("有100万")
class Man(Person):
    def money(self):
        # Person.money(self)        #方法一
        # super().money()           #方法二
        super(Man,self).money()     #方式三
        print("再赚1000万")

man = Man()
man.money()

# 新式类的写法
# 第一种
# class A: #经典类：不由任意内置类型派生出的类
#     pass
class Animal:
    def walk(self):
        print("我会走路")
class Dog(Animal):
    name="富贵"
    def bite(self):     #dog类是派生类
        print("我会咬人")
    # pass #不是派生类

# 第二种写法
# class A()
# 第三种写法 继承了object 类或者该类的子类都是新式类  --推荐使用
# class A(object)

# 多继承
# 子类可以拥有多个父类，并且拥有所有父类的属性和方法
class Father(object):
    def money(self):
        print("拥有100万财产被继承")
class Mother(object):
    def apprearance(self):
        print("绝世容颜需要被继承")
class Son(Father,Mother):
    pass #空语句，自动跳过

son = Son()
son.money()
son.apprearance()

# 不同的类具有同名的方法（实际开发应避免）
class Father(object):
    def money(self):
        print("拥有100万财产被继承")
class Mother(object):
    def money(self):
        print("拥有120万财产被继承")
    def apprearance(self):
        print("绝世容颜需要被继承")
class Son(Father,Mother):
    pass #空语句，自动跳过
son = Son()
son.money()
son.apprearance()
# 有多个父类的属性和方法，如果多个父类具有同名方法的时候，调用就近原则（括号内哪个写在前边，调用哪个类的方法）
# 了解：方法的搜索顺序
# python中内置的属性__mro__可以查看方法搜索顺序
# 搜索方法时，会先按照__mro__的输出结果，从左往右的顺序查找。
# 如果在当前类中找到了方法，就直接执行，不再搜索
# 如果找到最后一个类，还没有找到这个方法，程序就会报错
print(Son.__mro__)

# 多继承弊端
# 容易引发冲突



